package cn.yangliu.jdbc.dymanicdb;

import cn.yangliu.comm.tools.StringUtils;
import cn.yangliu.jdbc.annotation.DynamicDataSource;
import cn.yangliu.comm.BaseComponent;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * 数据源切换
 *
 * @author Xiong Hao
 */
@Aspect
@Component
@Order(1)
public class DynamicDataSourceAspect extends BaseComponent {


    /**
     * DynamicDataSource Pointcut
     */
    @Pointcut("@annotation(cn.yangliu.jdbc.annotation.DynamicDataSource)")
    public void dynamicDataSourceAdvice() {
    }

    /**
     * service Pointcut
     */
    @Pointcut("execution(* cn.yangliu.service.impl..*.*(..)))")
    public void serviceAdvice() {
    }

    /**
     * @DynamicDataSource 数据源切换
     * @param proceedingJoinPoint
     * @return
     */
    @Around(value = "dynamicDataSourceAdvice()")
    public Object dynamicDataSourceAdviceAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        return serviceAdviceAround(proceedingJoinPoint);
    }

    private String getAnnotationDatasource(ProceedingJoinPoint proceedingJoinPoint) throws NoSuchMethodException {
        Method objMethod = proceedingJoinPoint.getTarget().getClass().getMethod(proceedingJoinPoint.getSignature().getName(),
                ((MethodSignature) proceedingJoinPoint.getSignature()).getParameterTypes());
        DynamicDataSource methodAnnotation = objMethod.getAnnotation(DynamicDataSource.class);
        DynamicDataSource classAnnotation = proceedingJoinPoint.getTarget().getClass().getAnnotation(DynamicDataSource.class);
        String datasourceName = null;
        if (methodAnnotation != null && StringUtils.isNotEmpty(methodAnnotation.value().getTarget())) {
            logger.debug("set methon annotation datasource.===>" + methodAnnotation.value());
            datasourceName = methodAnnotation.value().getTarget();
        } else if (classAnnotation != null && StringUtils.isNotEmpty(classAnnotation.value().getTarget())) {
            logger.debug("set class annotation datasource.===>" + classAnnotation.value());
            datasourceName = classAnnotation.value().getTarget();
        }
        return datasourceName;
    }

    /**
     * service 数据源切换
     * @param proceedingJoinPoint
     * @return
     */
    @Around(value = "serviceAdvice()")
    public Object serviceAdviceAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        try {
            String datasourceName = getAnnotationDatasource(proceedingJoinPoint);
            if (datasourceName != null) {
                DataSourceContextHolder.setDataSourceType(datasourceName);
            }
            return proceedingJoinPoint.proceed();
        } finally {
            DataSourceContextHolder.clearDataSourceType();
        }
    }

}
